//
// Created by DELL on 2023/3/27.
//
#pragma once
#include <vector>
#include <list>
#include <mutex>

class MemoryPool
{
public:
    MemoryPool() = default;
    virtual ~MemoryPool() = default;

    void* allocate(std::size_t size);
    void free(void* p);

private:

    struct Chunk;
    struct Block
    {
        Chunk* chunk{};
        void* start{};
        uint32_t size{};
        bool isAllocated{false};
        Block() = default;
        Block(Chunk* c, void* s, uint32_t size, bool allocated)
            : chunk(c), start(s), size(size), isAllocated(allocated){}
    };

    struct Chunk
    {
        void *p{};
        uint32_t size{};
        std::list<Block> blocks;
        Chunk() noexcept = default;
        Chunk(void *p, uint32_t s) noexcept: p(p), size(s) {}
    };

    constexpr static uint32_t MinChunkSize  = 1 << 20; // 2^20 1MB
    constexpr static uint32_t MaxChunkSize  = 1 << 25; // 2^25 32MB
    constexpr static uint32_t MinBlockSize = 16;

    Chunk* createChunk(uint32_t size);
    void addFreeBlock(Block* block);
    void removeFreeBlock(Block* block);

    std::mutex mutex;
    std::list<Chunk> chunks;
    std::vector<Block*> freeBlocks;
};
